package edu.gettysburg.catapp1; 

/** 
 * ViewMap Activity extends MapActivity and implements LocationListener.  
 * ViewMap is used to track the user's location and to make sure they stay 
 * on the tour's path. 
 *  
 * @author Patrice Bramble 
 * @version 1.0 11/20/2012 
 */ 

import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.List;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

import android.annotation.SuppressLint;
import android.app.AlertDialog;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.IntentFilter.MalformedMimeTypeException;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Point;
import android.graphics.drawable.Drawable;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.location.LocationProvider;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Vibrator;
import android.provider.Settings;
import android.text.method.ScrollingMovementMethod;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.Button;
import android.widget.ImageButton;
import android.widget.TextView;
import android.widget.Toast;

import com.google.android.maps.GeoPoint;
import com.google.android.maps.MapActivity;
import com.google.android.maps.MapController;
import com.google.android.maps.MapView;
import com.google.android.maps.MyLocationOverlay;
import com.google.android.maps.Overlay;
import com.google.android.maps.OverlayItem;
import com.google.android.maps.Projection;

public class ViewMap extends MapActivity implements LocationListener{ 

	private MapView mapView;  
	private MapController mc; 
	private List<Overlay> mapOverlays; 
	private MapOverlay Sites; 
	private LocationManager lm; 
	private ArrayList<GeoPoint> sitePoints;
	private ArrayList<GeoPoint> allPoints; 
	private ArrayList<String> titles;
	private Projection projection; 
	private PathOverlay overlay; 
	private Path path; 
	private Path path2; 
	private MyLocationOverlay mlo; 
	private boolean GPSEnabled = true;
	private Animation animShow, animHide;
	private PendingIntent pIntent;
	private TransparentPanel ppanel;

	private ArrayList<Location> hotspotsLoc;
	private ArrayList<String> hotspotsDesc;

	private static final long MIN_TIME = 1; //in milliseconds
	private static final float MIN_DISTANCE = 1; // in meters
	private static final int ZOOM = 16;
	private static final float RADIUS = 1000; // in Meters
	private static final long ALERT_EXPIRATION = -1;
	private static final String APP_PACK = "edu.gettysburg.catapp1";

	private static final String PROX_INTENT = "edu.gettysburg.catapp1.PROXIMITY_ALERTS";

	private class getData extends AsyncTask<String, Integer, Long>{
		protected void onPreExecute(){
			setupMap();
		}
		protected void onProgressUpdate(Integer... progress) {			
		}

		@Override
		protected Long doInBackground(String... params) {

			return 0L;
		}	
		protected void onPostExecute(Long result) {
		}
	}


	@SuppressLint("ShowToast")
	@Override 
	/** 
	 * Sets up the viewmap activity and renders the viewmap_layout 
	 * @param savedInstanceState 
	 */ 
	public void onCreate(Bundle savedInstanceState) { 
		super.onCreate(savedInstanceState); 
		setContentView(R.layout.viewmap_layout);
		new getData().execute(); 
		ppanel.setVisibility(View.GONE);

	} 

	public void initPopup(String desc) {
		final TransparentPanel popup = (TransparentPanel) findViewById(R.id.alertWindow);
		popup.setVisibility(View.VISIBLE);

		animHide = AnimationUtils.loadAnimation( getBaseContext(), R.anim.popup_hide);

		final ImageButton   hideButton = (ImageButton) findViewById(R.id.hide_popup_button);
		hideButton.setOnClickListener(new View.OnClickListener() {
			public void onClick(View view) {
				popup.startAnimation( animHide );
				popup.setVisibility(View.INVISIBLE);
			}});

		final TextView locationName = (TextView) findViewById(R.id.location_name);
		final TextView locationDescription = (TextView) findViewById(R.id.location_description);

		//locationName.setText(name);
		locationDescription.setText(desc);
		locationDescription.setMovementMethod(new ScrollingMovementMethod());
	}


	/** 
	 * This method is called when the map activity is touched 
	 * @param m - MotionEvent 
	 */ 
	public boolean onTouchEvent(MotionEvent m, MapView v){ 
		return false; 
	} 

	/** 
	 * Sets up the mapview by making sure GPS is enabled and retrieving and 
	 * plotting path and site location 
	 */ 
	public void setupMap(){ 
		//Adds panel of rotating progress bar while the map is being setup
		ppanel = (TransparentPanel) findViewById(R.id.progressPanel);
		ppanel.setVisibility(View.VISIBLE);

		mapView = (MapView) findViewById(R.id.mapview); 
		mapView.setBuiltInZoomControls(true); 
		mc=mapView.getController(); 

		if(GPSEnabled){
			lm = (LocationManager)getSystemService(Context.LOCATION_SERVICE);  
			lm.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, MIN_TIME, MIN_DISTANCE, this); 
		}


		allPoints = TourOverview.TOUR_OBJECT.getAllGeoPoints(); 
		sitePoints = TourOverview.TOUR_OBJECT.getSiteGeoPoints();
		titles = TourOverview.TOUR_OBJECT.getSites();

		mapOverlays = mapView.getOverlays(); 
		projection = mapView.getProjection(); 


		mlo = new MyLocationOverlay(this,mapView);  
		mlo.enableCompass();  
		mlo.enableMyLocation(); 


		Drawable drawable = this.getResources().getDrawable(R.drawable.star); 
		Sites = new MapOverlay(drawable, this); 

		for(GeoPoint loc : sitePoints) {
			OverlayItem overlayItem = new OverlayItem(loc, titles.get(sitePoints.indexOf(loc)), "Latitude: " + loc.getLatitudeE6()/1E6 + "\nLongitude: " + loc.getLongitudeE6()/1E6); 
			Sites.addOverlay(overlayItem); 
		}
		overlay = new PathOverlay(allPoints, sitePoints, mapView);  

		if(allPoints.size() > 0){ 
			int index = allPoints.size()/2; 
			mc.setCenter(allPoints.get(index)); 
		} 

		//addAlerts(alertPoints, altText);
		mc.setZoom(ZOOM);
		mapOverlays.add(overlay);
		mapOverlays.add(Sites);
		mapOverlays.add(mlo);

		final Button b1 = (Button) findViewById(R.id.btn1);
		final Button b2 = (Button) findViewById(R.id.btn2);

		//Takes user to the previous page
		b1.setOnClickListener(new View.OnClickListener() {
			public void onClick(View v) {
				onBackPressed();
			}
		});

		//Takes user to the next stage of the tour
		b2.setOnClickListener(new View.OnClickListener() {
			public void onClick(View v) {
				InitialSite.SITE_NUM++;
				Intent intent = new Intent(getBaseContext(), InitialSite.class);
				startActivity(intent);
			}
		});

		hotspotsLoc = new ArrayList<Location>();
		hotspotsDesc = new ArrayList<String>();

		Location l = new Location("point");


		l.setLatitude(-33.121212);
		l.setLongitude(12.121212);
		hotspotsLoc.add(l);
		hotspotsDesc.add("Masters Hall");

		l.setLatitude(0);
		l.setLongitude(0);
		hotspotsLoc.add(l);
		hotspotsDesc.add("Somewhere");

		l.setLatitude(39.834538);
		l.setLongitude(-77.235485);
		hotspotsLoc.add(l);
		hotspotsDesc.add("You are now approaching Oak Ridge. Union' soldiers here held stubbornly against Rode's advance. By 3:30pm however, the entire Union line from here to McPherson Ridge had begun to crumble, finally falling back to Cemetery Hill.");

		addAlerts(hotspotsLoc, hotspotsDesc);
	} 


	class AlertReceiver extends BroadcastReceiver{
		ArrayList<String> alerts;

		AlertReceiver(ArrayList<String> alts){
			this.alerts = alts;
		}
		public void onReceive(Context context, Intent intent) {
			int kVal = (Integer) intent.getBundleExtra("extras").get("id");
			Toast.makeText(getBaseContext(), intent.getAction(), Toast.LENGTH_SHORT).show();

			//if(intent.getAction().equals(PROX_INTENT + k)) {
			//Toast.makeText(getBaseContext(), "" + kVal, Toast.LENGTH_SHORT).show();

			// Vibrate
			Vibrator vibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
			vibrator.vibrate(500);
			initPopup(alerts.get(kVal));
			//}
		}
	};

	/**
	 * Adds proximity alerts such that once the user approaches 
	 * one of the given points, they are alerted with an informative
	 * message. 
	 * @param points - points added for proximity alerts
	 * @param alts - alerts to be displayed
	 */
	//	public void addAlerts(ArrayList<Location> points, ArrayList<String> alts){
	//		IntentFilter filter = new IntentFilter();
	//
	//		for(int i = 0; i<points.size(); i++){
	//			Bundle extras = new Bundle();
	//			extras.putString("name", "alert"+i);
	//			extras.putInt("id", i);
	//			Intent intent = new Intent();
	//			intent = intent.setAction(PROX_INTENT+i);
	//			intent.addCategory(LocationManager.KEY_PROXIMITY_ENTERING);
	//			intent.putExtra(LocationManager.KEY_PROXIMITY_ENTERING, extras);
	//
	//			PendingIntent proxIntent = PendingIntent.getBroadcast(getBaseContext(), i, intent, PendingIntent.FLAG_CANCEL_CURRENT);
	//			lm.addProximityAlert(points.get(i).getLatitude(),points.get(i).getLongitude(),RADIUS,ALERT_EXPIRATION, proxIntent);
	//
	//			filter.addAction(PROX_INTENT+i);
	//		}
	//		filter.addCategory(LocationManager.KEY_PROXIMITY_ENTERING);
	//		registerReceiver(new AlertReceiver(alts), filter);
	//	}
	public void addAlerts(ArrayList<Location> points, ArrayList<String> alts){
		IntentFilter filter = new IntentFilter();
		ArrayList<PendingIntent> pIntents = new ArrayList<PendingIntent>();
		for(int i = 0; i<points.size(); i++){
			Bundle extras = new Bundle();
			extras.putString("name", "alert"+i);
			extras.putInt("id", i);
			Intent intent = new Intent(PROX_INTENT+ i);
			//intent = intent.setAction(PROX_INTENT + i);
			//intent.addCategory(LocationManager.KEY_PROXIMITY_ENTERING);
			//intent.putExtra(LocationManager.KEY_PROXIMITY_ENTERING, extras);

			PendingIntent proxIntent = PendingIntent.getBroadcast(getBaseContext(), i, intent, PendingIntent.FLAG_CANCEL_CURRENT);
			pIntents.add(proxIntent);
			lm.addProximityAlert(points.get(i).getLatitude(),points.get(i).getLongitude(),RADIUS,ALERT_EXPIRATION, pIntents.get(i));

			//filter.addAction(PROX_INTENT+i);
		}
		//filter.addCategory(LocationManager.KEY_PROXIMITY_ENTERING);
		filter = new IntentFilter(PROX_INTENT);
		registerReceiver(new AlertReceiver(alts), filter);
	}

	//	/** 
	//	 * Retrieves all site and path information from an xml feed 
	//	 */ 
	//	private void refreshItems() { 
	//		// XML stuff 
	//		URL url; 
	//		try { 
	//			String sitesFeed = "http://cs.gettysburg.edu/~lalvsa01/android/GCLocs.xml"; 
	//			url = new URL(sitesFeed); 
	//
	//			URLConnection connection; 
	//			connection = url.openConnection(); 
	//
	//			HttpURLConnection httpConnection = (HttpURLConnection)connection;  
	//			int responseCode = httpConnection.getResponseCode();  
	//
	//			if (responseCode == HttpURLConnection.HTTP_OK) {  
	//				InputStream in = httpConnection.getInputStream();  
	//
	//				DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); 
	//				DocumentBuilder db = dbf.newDocumentBuilder(); 
	//
	//				// parser 
	//				Document dom = db.parse(in);       
	//				Element docEle = dom.getDocumentElement(); 
	//
	//				// get all eqs 
	//				NodeList nl = docEle.getElementsByTagName("entry"); 
	//				if (nl != null && nl.getLength() > 0) { 
	//					for (int i = 0 ; i < nl.getLength(); i++) { 
	//						Element entry = (Element)nl.item(i); 
	//						Element title = (Element)entry.getElementsByTagName("title").item(0); 
	//						//Get title of site to add to overlay
	//						String t = title.getFirstChild().getNodeValue();
	//						Element g = (Element)entry.getElementsByTagName("georss:point").item(0); 
	//						Element link = (Element)entry.getElementsByTagName("link").item(0); 
	//						String pth = entry.getElementsByTagName("path").item(0).getFirstChild().getNodeValue(); 
	//
	//						String point = g.getFirstChild().getNodeValue(); 
	//						String[] location = point.split(" "); 
	//						Double lat = Double.parseDouble(location[0]) * 1e6; 
	//						Double lon = Double.parseDouble(location[1]) * 1e6; 
	//
	//						//Creates GeoPoint and add to itemizedOverlay 
	//						GeoPoint loc = new GeoPoint(lat.intValue(), lon.intValue()); 
	//						allPoints.add(loc); 
	//
	//						OverlayItem overlayItem = new OverlayItem(loc, t, "Latitude: " + loc.getLatitudeE6() + "\nLongitude: " + loc.getLongitudeE6()); 
	//						Sites.addOverlay(overlayItem); 
	//
	//						// creates arraylist of path points 
	//						String[] gPaths = pth.split(" "); 
	//
	//						for (int p = 0; p < gPaths.length/2; p++) { 
	//							Double lt = Double.parseDouble(gPaths[p*2]) * 1e6; 
	//							Double ln = Double.parseDouble(gPaths[p*2+1]) * 1e6; 
	//							allPoints.add(new GeoPoint(lt.intValue(), ln.intValue())); 
	//						} 
	//					} 
	//				} 
	//			} 
	//		} catch (MalformedURLException e) { 
	//			e.printStackTrace(); 
	//		} catch (IOException e) { 
	//			e.printStackTrace(); 
	//		} catch (ParserConfigurationException e) { 
	//			e.printStackTrace(); 
	//		} catch (SAXException e) { 
	//			e.printStackTrace(); 
	//		} 
	//		finally { 
	//		} 
	//	}

	/**
	 * Determines whether or not the GPS is currently activated
	 * @param context - Context for the base application
	 * @return true if the GPS is activated, false, if the GPS is not activated
	 */
	private boolean isGPSActivated(Context context) {
		return ((LocationManager) context.getSystemService(Context.LOCATION_SERVICE)).isProviderEnabled(LocationManager.NETWORK_PROVIDER)
				&& ((LocationManager) context.getSystemService(Context.LOCATION_SERVICE)).isProviderEnabled(LocationManager.NETWORK_PROVIDER);
	}


	public void onLocationChanged(Location location) { 
		if(GPSEnabled){
			if (location != null) { 
				Double lat = location.getLatitude() * 1e6; 
				Double lng = location.getLongitude() * 1e6; 
				GeoPoint gp = new GeoPoint(lat.intValue(), lng.intValue());     
				mc.animateTo(gp); 
				mc.setCenter(gp); 

				//addAlerts(hotspotsLoc, hotspotsDesc);
			}
		}
	} 

	public void onProviderDisabled(String provider) {

	} 

	public void onProviderEnabled(String provider) { 
		// TODO Auto-generated method stub 

	} 

	public void onStatusChanged(String provider, int status, Bundle extras) { 
		if(status == LocationProvider.TEMPORARILY_UNAVAILABLE || status == LocationProvider.OUT_OF_SERVICE){
			new AlertDialog.Builder(this).setMessage("You have lost your network connection").setNeutralButton("Ok", new DialogInterface.OnClickListener() {
				public void onClick(DialogInterface dialog, int which) {
					dialog.dismiss();
				}
			}).show();
			GPSEnabled = false;
			lm.removeUpdates(this);
		}
		else if(status == LocationProvider.AVAILABLE){
			new AlertDialog.Builder(this).setMessage("You now have a network connection").setNeutralButton("Ok", new DialogInterface.OnClickListener() {
				public void onClick(DialogInterface dialog, int which) {
					dialog.dismiss();
				}
			}).show();
			GPSEnabled = true;
			lm.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, MIN_TIME, MIN_DISTANCE, this);
		}

	} 

	@Override 
	protected boolean isRouteDisplayed() { 
		// TODO Auto-generated method stub 
		return false; 
	} 

	protected void onStart(){
		super.onStart();
		//Checks to see if GPS is enable
		//If not, leads user to enabling GPS
		if(!isGPSActivated(this) && GPSEnabled){
			new AlertDialog.Builder(this).setMessage("GPS is required.").setCancelable(false).setPositiveButton("Enable GPS", new DialogInterface.OnClickListener() {
				public void onClick(DialogInterface dialog, int id) {
					startActivity(new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS));
				}
			}).setNegativeButton("Exit", new DialogInterface.OnClickListener() {
				public void onClick(DialogInterface dialog, int id) {
					dialog.cancel();
					finish();
				}
			}).setNeutralButton("Ignore and Continue", new DialogInterface.OnClickListener() {
				public void onClick(DialogInterface dialog, int which) {
					GPSEnabled = false;
					dialog.cancel();
				}
			}).create().show();
		}
		if(isGPSActivated(this) && GPSEnabled){
			lm.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, MIN_TIME, MIN_DISTANCE, this);
			mlo.enableMyLocation();
		}
	}


	protected void onPause(){
		super.onPause();
		if(GPSEnabled){
			lm.removeUpdates(this);
			mlo.disableMyLocation();
			//lm.removeProximityAlert(proximityIntent);
		}
	}

	protected void onStop(){
		super.onStop();
		if(GPSEnabled){
			lm.removeUpdates(this);
			mlo.disableMyLocation();
		}
	}


}